package com.zx._01_基础._012_反射;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import org.junit.Test;

public class ReflectModelClassTest {

    /**
     * 操作类
     *
     * @throws ClassNotFoundException
     * @date: 2018年12月9日下午9:16:46
     * @author: zhangxue
     */
    @Test
    public void classHandler() throws Exception {
        //获取需要的类的三种方式
        // a. 直接获得
        Class<?> clazz = ReflectModel.class;
        // b. 通过类的实例获得
        ReflectModel model = new ReflectModel();
        clazz = model.getClass();
        // c. 根据全限定类名字符串获得class
        clazz = Class.forName("com.zx._01_基础._012_反射.ReflectModel");

        System.out.println("1.获得全限定名称：" + clazz.getName());

        System.out.println("2.获得简单名称：" + clazz.getSimpleName());

        System.out.println("3.获得修饰符：" + Modifier.toString(clazz.getModifiers()));

        System.out.println("4.创建类的实例 只能调用空参构造来获得类的实例:" + clazz.newInstance());

        System.out.println("5.获得这个类的父类(extend)" + clazz.getSuperclass());

        System.out.println("6.获得这个类所在的包:" + clazz.getPackage());

        // 7.获得 类实现的接口(impl)
        Class<?>[] interfaces = clazz.getInterfaces();
        System.out.println("7.获得 类实现的接口(impl)" + Arrays.toString(interfaces));

        //8.获得全部的构造器
        Constructor<?>[] cas = clazz.getDeclaredConstructors();
        System.out.println("8.全部的构造器" + Arrays.toString(cas));

        //9.获得public构造器
        Constructor<?>[] cs = clazz.getConstructors();
        System.out.println("9.全部public构造器" + Arrays.toString(cs));

        //10.全部方法
        Method[] mas = clazz.getDeclaredMethods();
        System.out.println("10.全部方法" + Arrays.toString(mas));

        //11.全部public方法
        Method[] ms = clazz.getMethods();
        System.out.println("11.全部public方法" + Arrays.toString(ms));

        //12.根据方法名称和参数类型，获得方法
        Method method = clazz.getMethod("info", String.class);
        System.out.println("12.根据方法名称和参数类型，获得方法" + method);

        //13.获得全部注解
        Annotation[] as = clazz.getAnnotations();
        System.out.println("13.获得全部注解" + Arrays.toString(as));

        //14.获得指定类型的注解,获得类上的注解
        Deprecated de = clazz.getAnnotation(Deprecated.class);
        System.out.println("14.获得指定类型的注解" + de);

        //15.使用全限定路径获得类，$或的这个类下指定的内部类
        Class<?> ct = Class.forName("com.zx._01_基础._012_反射.ReflectModel$HaHa");
        System.out.println("15.使用全限定路径获得类，$或的这个类下指定的内部类" + ct);

        //16.获得这个内部类的外部类
        Class<?> dc = ct.getDeclaringClass();
        System.out.println("16.获得这个内部类的外部类" + dc);

        //17.获得全部内部类
        Class<?>[] clas = clazz.getDeclaredClasses();
        System.out.println("17.获得全部内部类" + Arrays.toString(clas));

        // 18.特殊的类获得类型
        System.out.println(void.class.getName());
        System.out.println(int.class.getName());
    }


    // 操作构造函数
    @Test
    public void ConstructorHandler() throws Exception {
        Class<ReflectModel> clazz = ReflectModel.class;
        // 1.获得多个(共有)
        clazz.getConstructors();
        // 2.获得多个(共有私有)
        clazz.getDeclaredConstructors();
        // 3.获得指定的构造
        // clazz.getConstructor(String.class);//不能调用私有构造函数
        Constructor<ReflectModel> constructor = clazz.getDeclaredConstructor(String.class);

        //1 获得构造的修饰符
        String mod = Modifier.toString(constructor.getModifiers());
        System.out.println(mod);

        //2获得名称
        String name = constructor.getName();
        System.out.println(name);

        //3 获得参数列表
        Class[] params = constructor.getParameterTypes();
        System.out.println(params);

        //4 获得构造函数的异常信息
        Class[] exps = constructor.getExceptionTypes();
        System.out.println(exps);

        //5.通过构造创建对象(私有创建需要设置constructor.setAccessible(true),但是 不推荐,破坏封装性)
        constructor.setAccessible(true);
        ReflectModel obj = (ReflectModel) constructor.newInstance("666");
        System.out.println(obj);
    }


    // 操作属性
    @Test
    public void MethodHandler() throws Exception {
        ReflectModel reflectModel = new ReflectModel();
        //获取需要的类
        Class<ReflectModel> clazz = ReflectModel.class;
        //获得所有方法 (包括父类继承过来的)
        clazz.getMethods();
        //获得所有方法 (不包括父类继承过来的)
        clazz.getDeclaredMethods();
        //获得指定方法
        Method info = clazz.getMethod("info");
        Method info1 = clazz.getDeclaredMethod("info", String.class);

        Method m = info1;

        //获得修饰符
        String mod = Modifier.toString(m.getModifiers());

        //获得返回值
        Class returnT = m.getReturnType();

        //方法名
        String name = m.getName();

        //参数列表
        Class[] params = m.getParameterTypes();

        //异常信息
        Class[] excps = m.getExceptionTypes();

        //运行该方法(非静态)
        m.invoke(reflectModel, "666");

        //运行该方法(静态),静态方法调用我们知道不需要对象
        Method go = clazz.getMethod("go", String.class);
        go.invoke(null, "go");

    }

    // 操作属性
    @Test
    public void fieldHandler() throws Exception {
        //获取需要的类
        Class<ReflectModel> clazz = ReflectModel.class;
        //获得所有字段(不包括私有)
        Field[] fields = clazz.getFields();

        //获得所有字段(包括私有)
        fields = clazz.getDeclaredFields();

        //获得指定字段(不包括私有)
        Field field = clazz.getField("name");

        //获得指定字段(包括私有)
        field = clazz.getDeclaredField("name");

        //修饰符
        String mod = Modifier.toString(field.getModifiers());

        //属性的类型
        Class type = field.getType();

        //属性名称
        String name = field.getName();
    }

    // 操作对象
    @Test
    public void objectHandler() throws Exception {
        //获得类
        Class clazz = ReflectModel.class;

        //创建一个实例
        ReflectModel user = (ReflectModel) clazz.newInstance();

        //获得指定的属性
        Field name = clazz.getDeclaredField("name");

        //取消访问限制
        name.setAccessible(true);

        //为user对象的name属性赋值
        name.set(user, "小明");

        System.out.println(user.toString());
    }

    // 操作数组
    @Test
    public void arrayHandler() throws Exception {
        // 一维数组
        Object arr = Array.newInstance(String.class, 10);
        Array.set(arr, 5, "demo5");
        Array.set(arr, 6, "demo6");
        Object o5 = Array.get(arr, 5);
        System.out.println(o5);
        System.out.println(Arrays.toString((String[]) arr));

        // 创建一个三维数组
        //3,4,10放在XYZ坐标系中，相当于x轴长度为3，y轴长度为4，z轴长度为5。
        arr = Array.newInstance(String.class, 3, 4, 5);
        Object o2 = Array.get(arr, 2);
        Array.set(o2, 3, new String[]{"1", "1", "1", "1"});
        String[][][] aa = (String[][][]) arr;
        for (int i = 0; i < aa.length; i++) {
            for (int j = 0; j < aa[i].length; j++) {
                System.out.print(i + "." + j + ".");
                System.out.println(Arrays.toString(aa[i][j]));
            }
        }
    }

}
